#!/bin/sh

export E2E_PULLED_IMAGES_PATH="${E2E_PULLED_IMAGES_PATH:-$TARGET_PATH/pulled-images}"

start_background_repository_cache() {
  if [ "$E2E_DISABLE_CACHE" = "true" ]
  then
    echo "Repository cache disabled"
    return
  fi
  notrace_function traceable_start_background_repository_cache "$@"
}

traceable_start_background_repository_cache() {
  cache_pulled_images_to_local_repository &
  trap_kill "$!"
  load_failed_images_pull_from_local_repository &
  trap_kill "$!"
}

setup_repository_cache() {
  if [ "$E2E_DISABLE_CACHE" = "true" ]
  then
    echo "Repository cache disabled"
    return
  fi
  notrace_function traceable_setup_repository_cache "$@"
}

traceable_setup_repository_cache() {
  load_cached_images_from_local_repository
}

set_up_private_repository() {
  export PRIVATE_REPO_URI="$(get_private_repository_uri)"
  export PRIVATE_REPO_USER="$(get_private_repository_user)"
  export PRIVATE_OPERATOR_IMAGE_NAME="${PRIVATE_REPO_URI}${OPERATOR_PUBLIC_REGISTRY_PATH%/}/operator:$IMAGE_TAG"
  export PRIVATE_RESTAPI_IMAGE_NAME="${PRIVATE_REPO_URI}${OPERATOR_PUBLIC_REGISTRY_PATH%/}/restapi:$IMAGE_TAG"
  export PRIVATE_ADMINUI_IMAGE_NAME="${PRIVATE_REPO_URI}${OPERATOR_PUBLIC_REGISTRY_PATH%/}/admin-ui:$ADMINUI_IMAGE_TAG"
  export PRIVATE_JOBS_IMAGE_NAME="${PRIVATE_REPO_URI}${OPERATOR_PUBLIC_REGISTRY_PATH%/}/jobs:$IMAGE_TAG"
  export PRIVATE_CLUSTER_CONTROLLER_IMAGE_NAME="${PRIVATE_REPO_URI}${OPERATOR_PUBLIC_REGISTRY_PATH%/}/cluster-controller:$IMAGE_TAG"
  export PRIVATE_STREAM_IMAGE_NAME="${PRIVATE_REPO_URI}${OPERATOR_PUBLIC_REGISTRY_PATH%/}/stream:$IMAGE_TAG"

  if ! use_alternative_registry
  then
    get_private_repository_password | docker login --username AWS --password-stdin "$PRIVATE_REPO_URI"

    docker tag "$OPERATOR_IMAGE_NAME" "$PRIVATE_OPERATOR_IMAGE_NAME"
    docker tag "$RESTAPI_IMAGE_NAME" "$PRIVATE_RESTAPI_IMAGE_NAME"
    docker tag "$JOBS_IMAGE_NAME" "$PRIVATE_JOBS_IMAGE_NAME"
    docker tag "$ADMINUI_IMAGE_NAME" "$PRIVATE_ADMINUI_IMAGE_NAME"
    docker tag "$CLUSTER_CONTROLLER_IMAGE_NAME" "$PRIVATE_CLUSTER_CONTROLLER_IMAGE_NAME"
    docker tag "$DISTRIBUTEDLOGS_CONTROLLER_IMAGE_NAME" "$PRIVATE_DISTRIBUTEDLOGS_CONTROLLER_IMAGE_NAME"
    docker tag "$STREAM_IMAGE_NAME" "$PRIVATE_STREAM_IMAGE_NAME"

    local NAME
    for NAME in operator restapi admin-ui jobs \
      cluster-controller stream
    do
      if ! aws ecr describe-repositories --repository-name "stackgres/$NAME" > /dev/null 2>&1
      then
        aws ecr create-repository --repository-name "stackgres/$NAME"
      fi
    done

    docker push "$PRIVATE_OPERATOR_IMAGE_NAME"
    docker push "$PRIVATE_RESTAPI_IMAGE_NAME"
    docker push "$PRIVATE_JOBS_IMAGE_NAME"
    docker push "$PRIVATE_ADMINUI_IMAGE_NAME"  
    docker push "$PRIVATE_CLUSTER_CONTROLLER_IMAGE_NAME"
    docker push "$PRIVATE_DISTRIBUTEDLOGS_CONTROLLER_IMAGE_NAME"
    docker push "$PRIVATE_STREAM_IMAGE_NAME"
  fi

  if kubectl get namespace "$OPERATOR_NAMESPACE" > /dev/null 2>&1
  then  
    kubectl get secret -n "$OPERATOR_NAMESPACE" regcred > /dev/null && kubectl delete secret -n "$OPERATOR_NAMESPACE" regcred
    kubectl create secret docker-registry -n "$OPERATOR_NAMESPACE" regcred \
      --docker-server="$PRIVATE_REPO_URI" \
      --docker-username="$PRIVATE_REPO_USER" \
      --docker-password="$(get_private_repository_password)"
  else
    kubectl create namespace "$OPERATOR_NAMESPACE"
    kubectl create secret docker-registry -n "$OPERATOR_NAMESPACE" regcred \
    --docker-server="$PRIVATE_REPO_URI" \
    --docker-username="$PRIVATE_REPO_USER" \
    --docker-password="$(get_private_repository_password)"
  fi

  if kubectl get serviceaccount -n "$OPERATOR_NAMESPACE" stackgres-operator > /dev/null 2>&1
  then
    kubectl delete serviceaccount -n "$OPERATOR_NAMESPACE" stackgres-operator
    cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: stackgres-operator
  namespace: $OPERATOR_NAMESPACE
imagePullSecrets:
- name: regcred
EOF
  fi

  if kubectl get serviceaccount -n "$OPERATOR_NAMESPACE" stackgres-restapi > /dev/null 2>&1
  then
    kubectl delete serviceaccount -n "$OPERATOR_NAMESPACE" stackgres-restapi
    cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: stackgres-restapi
  namespace: $OPERATOR_NAMESPACE
imagePullSecrets:
- name: regcred
EOF
  fi
}

get_private_repository_uri() {
  if use_alternative_registry
  then
    echo "$E2E_OPERATOR_REGISTRY$E2E_OPERATOR_REGISTRY_PATH"
  else
    local AWS_ACCOUNT_ID AWS_REGION
    AWS_ACCOUNT_ID="$(aws --output=text sts get-caller-identity | awk '{print $1}')"
    AWS_REGION="$(aws configure get region)"

    echo "$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com"
  fi
}

get_private_repository_user() {
  if use_alternative_registry
  then
    echo AWS
  else
    jq -r '.auths|to_entries|.[]|.key + "|" + .value.auth' "${HOME}/.docker/config.json" \
      | grep -F 'registry.gitlab.com' | head -n 1 | cut -d '|' -f 2 \
      | base64 -d | cut -d : -f 1
  fi
}

get_private_repository_password() {
  if use_alternative_registry
  then
    jq -r '.auths|to_entries|.[]|.key + "|" + .value.auth' "${HOME}/.docker/config.json" \
      | grep -F 'registry.gitlab.com' | head -n 1 | cut -d '|' -f 2 \
      | base64 -d | cut -d : -f 2
  else
    echo "$(aws ecr get-login-password)"
  fi
}

use_alternative_registry() {
  [ "$E2E_BUILD_IMAGES" = true ] || [ "$E2E_USE_ALTERNATIVE_REGISTRY" = true ]
}

load_cached_images_from_local_repository() {
  echo "Loading cached images from local repository"
  if [ ! -f "$E2E_PULLED_IMAGES_PATH" ]
  then
    touch "$E2E_PULLED_IMAGES_PATH"
  fi
  cat "$E2E_PULLED_IMAGES_PATH" \
    | grep -v ":$OPERATOR_PUBLIC_REGISTRY$OPERATOR_PUBLIC_REGISTRY_PATH" \
    | if [ "$OPERATOR_PUBLIC_REGISTRY" = quay.io ]
      then
        grep -v ":${OPERATOR_PUBLIC_REGISTRY_PATH%/}/"
      fi \
    | grep -v ":$COMPONENT_PUBLIC_REGISTRY$COMPONENT_PUBLIC_REGISTRY_PATH" \
    | if [ "$COMPONENT_PUBLIC_REGISTRY" = quay.io ]
      then
        grep -v ":${COMPONENT_PUBLIC_REGISTRY_PATH%/}/"
      fi \
    | cut -d : -f 2-3 | sort | uniq \
    | xargs_parallel_shell % "$E2E_PATH/e2e" load_cached_image_from_local_repository '%'
}

load_cached_image_from_local_repository() {
  if docker image inspect "$1" >/dev/null 2>&1
  then
    try_function load_image_k8s "$1"
    if ! "$RESULT"
    then
      echo "Loading image $IMAGE_NAME to k8s failed!"
    fi
  else
    echo "Image $1 not found in cache!"
  fi
}

cache_pulled_images_to_local_repository() {
  echo "Looking for pulled images to cache to local repository"
  if [ ! -f "$E2E_PULLED_IMAGES_PATH" ]
  then
    touch "$E2E_PULLED_IMAGES_PATH"
  fi
  wait_until kubectl get event --all-namespaces -o json >/dev/null 2>&1
  event_watch --follow \
    | stdbuf -o0 grep '\sSuccessfully pulled image "[^"]\+"' \
    | stdbuf -o0 sed 's/^.*\sSuccessfully pulled image "\([^"]\+\)".*$/\1/' \
    | (
      while read IMAGE_NAME
      do
        echo "Detected pulled image $IMAGE_NAME to k8s env $E2E_ENV"
        if [ "$(grep -F "$IMAGE_NAME" "$E2E_PULLED_IMAGES_PATH" \
          | sort | tail -n 1 | cut -d : -f 1 | grep '\d+' || echo 0)" \
          -lt "$(($(date +%s)-30))" ]
        then
          echo "Pulling image $IMAGE_NAME to cache"
          local EXIT_CODE RESULT
          try_function docker_pull "$IMAGE_NAME"
          if "$RESULT"
          then
            echo "$(date +%s):$IMAGE_NAME" >> "$E2E_PULLED_IMAGES_PATH"
          else
            echo "Pulling image $IMAGE_NAME to cache failed!"
          fi
        fi
      done
      )
}

load_failed_images_pull_from_local_repository() {
  echo "Looking for failed images pull to load from local repository"
  wait_until kubectl get event --all-namespaces -o json >/dev/null 2>&1
  event_watch --follow \
    | stdbuf -o0 grep '\s\(Failed to pull image\|Back-off pulling image\) "[^"]\+"' \
    | stdbuf -o0 sed 's/^.*\s\(Failed to pull image\|Back-off pulling image\) "\([^"]\+\)".*$/\2/' \
    | (
      while read IMAGE_NAME
      do
        echo "Detected failed to pull image $IMAGE_NAME to k8s env $E2E_ENV"
        if docker image inspect "$IMAGE_NAME" >/dev/null 2>&1
        then
          load_image_k8s "$IMAGE_NAME"
        else
          local EXIT_CODE RESULT
          try_function docker_pull "$IMAGE_NAME"
          if ! "$RESULT"
          then
            echo "Image $IMAGE_NAME not found in cache and can not be pulled!"
          fi
        fi
      done
      )
}

docker_pull() {
  local IMAGE_NAME="$1"
  local MAPPED_IMAGE_NAME="$(printf '%s' "$IMAGE_NAME" | eval "$(
    printf '%s\n' "$E2E_IMAGE_MAP" | tr ' ' '\n' \
      | grep -v '^$' | sed 's/=/#/g' \
      | {
        printf 'cat'
        while read -r SED_EXPR
        do
          printf " | sed 's#%s#'" "$SED_EXPR"
        done
        }
    )")"
  if [ "$MAPPED_IMAGE_NAME" != "$IMAGE_NAME" ]
  then
    echo "Using $MAPPED_IMAGE_NAME as $IMAGE_NAME"
  fi
  docker pull -q "$MAPPED_IMAGE_NAME"
  if [ "$K8S_USE_INTERNAL_REPOSITORY" = true ]
  then
    local RESULT EXIT_CODE
    try_function pull_image_k8s "$MAPPED_IMAGE_NAME"
    if ! "$RESULT"
    then
      load_image_k8s "$MAPPED_IMAGE_NAME"
    fi
  fi
  if [ "$MAPPED_IMAGE_NAME" != "$IMAGE_NAME" ]
  then
    docker_tag "$MAPPED_IMAGE_NAME" "$IMAGE_NAME"
  fi
}

docker_push() {
  local IMAGE_NAME="$1"
  docker push -q "$IMAGE_NAME"
}

docker_tag() {
  docker_local_tag "$1" "$2"
  if [ "$K8S_USE_INTERNAL_REPOSITORY" = true ]
  then
    tag_image_k8s "$1" "$2"
  fi
}

docker_local_tag() {
  docker tag "$1" "$2"
}
